#version 460
#extension GL_EXT_ray_tracing : require
#extension GL_EXT_scalar_block_layout : enable
#extension GL_EXT_nonuniform_qualifier : enable
#extension GL_GOOGLE_include_directive : enable
#extension GL_EXT_buffer_reference2 : require
#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require
#extension GL_EXT_shader_explicit_arithmetic_types_int16 : require
#extension GL_ARB_shader_clock : enable
#extension GL_EXT_shader_16bit_storage : enable



#include "../../../../core/shader_std.h"
#include "../../../../core/shader_built_in_functions.h"
#include "../../../../core/shader_PBR.h"
#include "../../../../core/shader_ob.h"


//#extension GL_EXT_debug_printf : enable
//debugPrintfEXT("Test");
//模型顶点类型
//全局统一数据类型
//layout(buffer_reference, scalar, std430) readonly buffer B_MaterialRef {S_Material M[]; };
//layout(binding = DEF_ObMeshBindID, scalar) readonly buffer B_ObjMesh { S_ObMesh m_Address[];} ObMesh;

layout(binding = 0, set = 0) uniform accelerationStructureEXT topLAS[];
layout(binding = 2, set = 0) uniform CameraProp {
	mat4 projInverse;
	mat4 viewInverse;
	mat4 projMat;
	mat4 viewMat;
} cam;

layout(binding = DEF_RenderFrameBindID, set = 0, scalar) uniform FrameProp {
	GLSL_RenderFrame renderFrame;
};
//layout(std430, scalar, binding = DEF_BINDING_Ray_ObMesh) readonly buffer B_Buf {
//	S_ObMesh m_Mesh[]; 
//}; 

layout(location = 0) rayPayloadInEXT S_Ray hitValue;
layout(location = 3) callableDataEXT S_SceneDataCall callSceneData;
//layout(location = 1) callableDataEXT S_Material callMaterial;

hitAttributeEXT vec2 attribs;
//gl_GeometryIndexEXT
//gl_InstanceCustomIndexEXT
//const uint g_SurfaceType_Faceforward = DEF_SurfaceType_Faceforward;
//const uint g_SurfaceType_Reflect = DEF_SurfaceType_Reflect;
//const uint g_SurfaceType_Refract = DEF_SurfaceType_Refract;
		   
void main(){
	
	if(hitValue.Depth > renderFrame.m_BouncesNum + 1 || hitValue.RayType == DEF_LigthReturnRayType) return; 
	//uint GeometryIndex = gl_InstanceCustomIndexEXT & DEF_RY_InstanceBitFlag;
	//uint GeometryIndex = gl_InstanceCustomIndexEXT;
	//uint GeometryIndex = gl_GeometryIndexEXT;
	R_GlobalParameter_UI64 addressRtOb = R_GlobalParameter_UI64(renderFrame.m_Address_RtOb);
	S_RtOb rtOb = B_RtOb(addressRtOb.ui64Ptr[0]).gRtOb[gl_InstanceCustomIndexEXT];


	uint obMask = rtOb.m_SceneMask_ObMask & 0x0000ffff;
	uint cullMask = rtOb.m_SceneMask_ObMask >> 16;
	uint flags = gl_RayFlagsOpaqueEXT;
	//uint cullMask = 0xff;
	float tmin = 0.0001;
	float tmax = 2000.0;
	vec3 origin = gl_WorldRayOriginEXT + gl_WorldRayDirectionEXT * gl_HitTEXT;

	uint seed = f_tea(gl_LaunchIDEXT.y * gl_LaunchSizeEXT.x + gl_LaunchIDEXT.x, int(clockARB()) ); 
	//uint seed = f_tea(gl_LaunchIDEXT.y * gl_LaunchSizeEXT.x + gl_LaunchIDEXT.x, 1); 
	
	S_ObMesh    Resource_ObMesh = ObMesh.m_Address[rtOb.m_AddressMesh];
	
	vec3 vert;
	vec3 normal;
	vec3 sidedNormal;
	vec3 barycentrics = vec3(1.0 - attribs.x - attribs.y, attribs.x, attribs.y);

	uint MaterialID = rtOb.m_MaterialID;
	uint OBType   = Resource_ObMesh.m_ObType;
	/*switch(OBType) {
		case DEF_ObType_Mesh : {
			
			B_Indexs    mesh_index = B_Indexs(Resource_ObMesh.m_AddressIndex);
			B_Vertices  mesh_vert  = B_Vertices(Resource_ObMesh.m_AddressVertex);
			
			//模型顶点元素数据
			B_Faces mesh_face = B_Faces(Resource_ObMesh.m_AddressFaces);
			//面元素
			S_FaceElement Element = mesh_face.Element[gl_PrimitiveID];


			uvec3 vertIndex = mesh_index.I[gl_PrimitiveID];
			vec3 v0 = mesh_vert.V[vertIndex.x].vert;
			vec3 v1 = mesh_vert.V[vertIndex.y].vert;
			vec3 v2 = mesh_vert.V[vertIndex.z].vert;

			vert = v0 * barycentrics.x + v1 * barycentrics.y + v2 * barycentrics.z;
			if(Element.FacesMooth > 0){
				normal = f_surface_FaceNormal(v0, v1, v2);
			} 
			else {
				normal = mesh_vert.V[vertIndex.x].normal * barycentrics.x + mesh_vert.V[vertIndex.y].normal * barycentrics.y + mesh_vert.V[vertIndex.z].normal * barycentrics.z;
			}
			sidedNormal = normalize(vec3(normal * gl_WorldToObjectEXT));
			//faceforward(sidedNormal, normal, gl_WorldRayDirectionEXT);
			
			if (MaterialID == 0) {
				MaterialID = Element.MaterialID;
			}
			break;
		}
		case DEF_ObType_Particle : {
			//return;
			S_Aabb mesh_vert = B_AABB(Resource_ObMesh.m_AddressVertex).gAabb[0];
			//B_AABB mesh_vert = B_AABB(Resource_ObMesh.m_AddressVertex);
			
			vec3 worldNrm = normalize(origin - (mesh_vert.minimum + (mesh_vert.maximum - mesh_vert.minimum) * 0.5) );
			vec3 absN = abs(worldNrm);
			float maxC = max(max(absN.x, absN.y), absN.z);
			sidedNormal = (maxC == absN.x) ? vec3(sign(worldNrm.x), 0, 0) :
										(maxC == absN.y) ? vec3(0, sign(worldNrm.y), 0) : vec3(0, 0, sign(worldNrm.z));
			//normal = vec3(1);	
			//sidedNormal = vec3(1);				
			break;
		}
	}*/

	
	B_Indexs    mesh_index = B_Indexs(Resource_ObMesh.m_AddressIndex);
	B_Vertices  mesh_vert  = B_Vertices(Resource_ObMesh.m_AddressVertex);
	
	//模型顶点元素数据
	B_Faces mesh_face = B_Faces(Resource_ObMesh.m_AddressFaces);
	//面元素
	S_FaceElement Element = mesh_face.Element[gl_PrimitiveID];

	uvec3 vertIndex = mesh_index.I[gl_PrimitiveID];
	vec3 v0 = mesh_vert.V[vertIndex.x].vert;
	vec3 v1 = mesh_vert.V[vertIndex.y].vert;
	vec3 v2 = mesh_vert.V[vertIndex.z].vert;

	vert = v0 * barycentrics.x + v1 * barycentrics.y + v2 * barycentrics.z;
	if(Element.FacesMooth > 0){
		normal = f_surface_FaceNormal(v0, v1, v2);
	} 
	else {
		normal = mesh_vert.V[vertIndex.x].normal * barycentrics.x + mesh_vert.V[vertIndex.y].normal * barycentrics.y + mesh_vert.V[vertIndex.z].normal * barycentrics.z;
	}
	sidedNormal = normalize(vec3(normal * gl_WorldToObjectEXT));
	//faceforward(sidedNormal, normal, gl_WorldRayDirectionEXT);
	
	if (MaterialID == 0) {
		MaterialID = Element.MaterialID;
	}
	
	//索引材质
	S_Material material = m_Material[ MaterialID ];
	
	if ( dot(sidedNormal, gl_WorldRayDirectionEXT) >= 0 ) {
		sidedNormal = -sidedNormal;
		//面类型 正面
		hitValue.SurfaceType |= DEF_SurfaceType_Faceforward;
	}else{
		//面类型 反面
		hitValue.SurfaceType &= DEF_SurfaceType_Faceforward ^ 0xffffffff;
	}
	
	
	
	callSceneData.reflect			= material.m_reflect - 0.0000001;
	callSceneData.rayDir			= gl_WorldRayDirectionEXT;
	callSceneData.PrimitiveIndex	= gl_PrimitiveID;
	callSceneData.InstanceIndex		= gl_InstanceCustomIndexEXT;
	//callSceneData.InstanceID		= rtOb.m_InstanceID;
	callSceneData.alpha 			= 1;
	

	//hitValue.Dis += gl_HitTEXT;
	//float hitDis = 1;
	float irradiance = 1;// = normalize(max(dot(irradianceDir, normal), 0));
	float transmission = material.m_transmission;
	uint Depth = hitValue.Depth;
	++hitValue.Depth;
	
	
	//vec2 texCoord = v0.texCoord * barycentrics.x + v1.texCoord * barycentrics.y + v2.texCoord * barycentrics.z;
	//float roughness = 1;
	// = normalize((f_SphereSampling_toWorld(TangentSample, normal) + (rv * (1-roughness) * 60) ));
	//float reflectIntensity =  material.m_refract;
	vec3 irradianceDir;
	float reflectIntensity =  0;
	uint mask = 0;

	if(hitValue.Depth < 8) {
		switch(OBType){
			case DEF_ObType_Ligth : {
				
				R_GlobalParameter_LigthArea LigthArea_GParam = R_GlobalParameter_LigthArea(gGlobalParam.m_AddressLigthArea);
				S_LightArea LightArea = LigthArea_GParam.LigthAreaPtr[gl_InstanceCustomIndexEXT >> DEF_RY_InstanceBitSize];

				mask = LightArea.m_mask;
				if ( (hitValue.LigthMask & LightArea.m_mask) != 0  && LightArea.m_enable != 0) {
					float color_dot = max(dot(normal, -gl_WorldRayDirectionEXT), 0);

					irradianceDir = gl_WorldRayDirectionEXT;
					hitValue.Color += LightArea.m_intensity * sign(color_dot) * hitValue.Alpha;
					//hitValue.Color = vec3(1,0,1);
					irradiance = color_dot;
					hitValue.irradiance += LightArea.m_intensity * sign(color_dot) * hitValue.Alpha;
					//hitValue.irradiance = 1;
					//callSceneData.Color = vec3(1);
				} else {
					callSceneData.Color = vec3(0.001);
					//callSceneData.reflect = 0.001;
				}
				//callSceneData.alpha = 0;
				hitValue.Alpha = 0;
				break;
			}
		}
	}
	
	//计算材质
	bool calMaterial = true;
	//光线穿透
	bool penetrate = false;

	bool maskBit = false;
	
	if(Depth == 0){
		hitValue.Normal = sidedNormal;
		hitValue.Diffuse = vec3(1,0,0);
		hitValue.Dis = gl_HitTEXT;

		switch(obMask){
			case DEF_Mask_Indirect : {
				calMaterial = false;
				penetrate = true;
				hitValue.SurfaceType |= DEF_SurfaceType_Entity; 
				break;
			}
			case DEF_Mask_Discard : {
				calMaterial = false;
				hitValue.Alpha = 0;
				return;
			}
			case DEF_Mask_Shadow : {
				hitValue.SurfaceType |= DEF_SurfaceType_Entity; 
				break;
			}
			default : {
				maskBit = true;
				break;
			}
		}
	}
	else {
		if ( bool(hitValue.SurfaceType & DEF_SurfaceType_Entity) ) {
			
			switch(obMask){
				case DEF_Mask_Indirect : {
					calMaterial = false;
					penetrate = true;
					break;
				}
				case DEF_Mask_Discard : {
					calMaterial = false;
					hitValue.Alpha = 0;
					return;
				}
				case DEF_Mask_Shadow : {
					break;
				}
				default : {
					hitValue.SurfaceType &= DEF_SurfaceType_Entity ^ 0xffffffff; 
					break;
				}
			}
		}
		else{
			maskBit = true;
		}
	}


	
	
	callSceneData.MaterialID   = MaterialID | (hitValue.SurfaceType << 16);
	callSceneData.Vert         = vert;
	callSceneData.irradiance   = hitValue.irradiance;
	callSceneData.barycentrics = barycentrics;
	callSceneData.roughness    = material.m_roughness;
	callSceneData.Normal       = sidedNormal;
	callSceneData.rayDir       = gl_WorldRayDirectionEXT;
	
	

	callSceneData.reflect = 0;
	if(calMaterial){
		if (material.m_shaderIndex >= 0) {
			executeCallableEXT(material.m_shaderIndex, 3);
			//callSceneData.Color = vec3(1,0,0);
		} else {
			callSceneData.Color += vec3(0.1);
			callSceneData.Vert = vec3(0.5);
			callSceneData.reflect = 0;

			callSceneData.Color = vec3(2,0,1.8);
		}
	}
	
	

	vec3 color = callSceneData.Color + 0.000001;
	float illuminate = callSceneData.reflect;
	
	vec2 noise = vec2(f_rnd(seed)*6.283185, f_rnd(seed + int(clockARB()) ) * 1.570796 * callSceneData.roughness);
	vec3 TangentSample = normalize(f_SphereSampling(noise));

	//bool external = true;
	switch(OBType){
		case DEF_ObType_Particle : 
		case DEF_ObType_Mesh : {
			float random = f_rnd( seed );

			
			if ( random >= callSceneData.alpha || penetrate) {
				irradianceDir = gl_WorldRayDirectionEXT;
				irradiance = 1;
				color = vec3(0);

				//hitValue.irradiance += 0.1;
			} else {
				if ( random >= transmission ) {
					vec3 rv = reflect(gl_WorldRayDirectionEXT, sidedNormal);
					irradianceDir = normalize(f_SphereSampling_toWorld(TangentSample, rv));
					
					//面类型 折射面
					hitValue.SurfaceType &= DEF_SurfaceType_Reflect | 0xffffff00;
				} 
				else {
					vec3 rv = refract(gl_WorldRayDirectionEXT, sidedNormal, material.m_refract);
					irradianceDir = normalize(f_SphereSampling_toWorld(TangentSample, rv));

					//面类型 发射面
					hitValue.SurfaceType &= DEF_SurfaceType_Refract | 0xffffff00;

				}
				
				irradiance = clamp(abs(dot(irradianceDir, sidedNormal)), 0.001, 1);
			}
			//irradianceDir= mix(irradianceDir, gl_WorldRayDirectionEXT, transmission);
			//hitValue.irradiance *= irradiance;
			//hitValue.Dir = irradianceDir;
			hitValue.LigthMask &= material.m_LigthMask;
			if(Depth > 0){
				hitValue.LigthDis += gl_HitTEXT * hitValue.Alpha;
			}
			//hitValue.Alpha = callSceneData.alpha;
			break;
		}
	default:
		hitValue.Alpha = 0;
	}
	
	
	
	if(hitValue.Depth < renderFrame.m_BouncesNum) {
		traceRayEXT(topLAS[0], flags, cullMask, 0, 0, 0, origin, tmin, irradianceDir, tmax, 0);
		
		vec3 w = vec3(0.2125,0.7154,0.0721);
		float luminance = dot(w, color);

		
		//hitValue.irradiance += clamp(1 - illuminate, 0, 1);

		vec3 finalColor = vec3(0);
		switch(obMask){
			case DEF_Mask_Indirect : {
				callSceneData.alpha = 0;
				break;
			}
			case DEF_Mask_Discard : {
				callSceneData.alpha = 0;
				break;
			}
			case DEF_Mask_Shadow : {
				break;
			}
			default : {
				
				break;
			}
		}

		float accumulatedLuminance = dot(w, hitValue.Color);
		finalColor = hitValue.Color + (color * accumulatedLuminance * irradiance);
		//自发光
		finalColor = mix(finalColor, callSceneData.Vert, clamp(illuminate, 0, 1));
		

		//透明
		hitValue.Color = mix(hitValue.Color, finalColor, callSceneData.alpha);
		
	}
	else{
		switch(hitValue.RayType){
			case DEF_LigthReturnRayType : {
				//hitValue.Color = vec3(1,0,0);
				return;
			}
			default: {
				if ( renderFrame.m_world_ShaderID >= 0 ) {
					callSceneData.rayDir = gl_WorldRayDirectionEXT;
					callSceneData.MaterialID = 0;
					callSceneData.PrimitiveIndex = 0;
					callSceneData.InstanceIndex = 0;
					callSceneData.Vert = gl_WorldRayDirectionEXT;
					callSceneData.ligthDir = gl_WorldRayDirectionEXT;
					callSceneData.Normal = -gl_WorldRayDirectionEXT;
					callSceneData.Color = vec3(0);
					executeCallableEXT(renderFrame.m_world_ShaderID, 3);
					
					vec3 w = vec3(0.2125,0.7154,0.0721);
					float luminance = max(dot(callSceneData.Color, w), 0);
					hitValue.Color += callSceneData.Color;
					hitValue.irradiance = luminance;
					return;
				}
				break;
			}
		}
	}

	if(hitValue.Depth >= renderFrame.m_BouncesNum) {
		
		hitValue.RayType = DEF_LigthReturnRayType;
		
		R_GlobalParameter_LigthPoint LigthPoint_GParam = R_GlobalParameter_LigthPoint(gGlobalParam.m_AddressLigthPoint);
		R_GlobalParameter_LigthSpot LigthSpot_GParam = R_GlobalParameter_LigthSpot(gGlobalParam.m_AddressLigthSpot);
		
		vec3 sphereSampling = f_SphereSampling_toWorld(TangentSample, sidedNormal);
		
		for(uint i=0; i<renderFrame.m_PointLightNum; ++i){
			S_LightPoint light = LigthPoint_GParam.LigthPointPtr[i];
			
			
			if( ((hitValue.LigthMask & light.m_mask) != 0) && (light.m_enable != 0) ) {
				vec3 ligthDir = light.m_pos - origin;
				float ligthArea = min(length(ligthDir), light.m_falloff);

				hitValue.Dis = ligthArea;
				ligthDir = normalize(ligthDir);
				hitValue.Ligth_Type_ID = ((DEF_ObType_Ligth_Point<<16) | i);
				callSceneData.ligthDir = ligthDir;
				
				traceRayEXT(topLAS[0], flags, cullMask, 0, 0, 0, origin + sphereSampling * light.m_size, 0.0001, ligthDir, ligthArea, 0);
			}
		}

		for(uint i=0; i<renderFrame.m_SpotLightNum; ++i){


		}

		for(uint i=0; i<renderFrame.m_ParallelLightNum; ++i){


		}
	}
	
}



